#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Predesys Server - Core - Address log management
@version: 0.2.5
@license: GPL 3.0 (see "license" file)
@author: Jose A. Jimenez
@contact: jajimc@gmail.com"""

import sys
sys.dont_write_bytecode = True
import os
import os.path
DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(os.path.join(DIR, "../errorlog"))
import errorlog
import time
import coreexceptions
import sqlalchemy
import data
import configuration

# Row limit
ROW_LIMIT = 10000
RECORD_MAX = 10000

def get_results_limit():
    """Gets the limit of rows of select sql sentences.
    @return: Row limit
    @rtype: C{int}"""
    global ROW_LIMIT
    return ROW_LIMIT

def get_log_addresses(limit):
    """Gets logged addresses.
    @param limit: Limit of addresses to get. It can be as much ROW_LIMIT.
    @type limit: C{int}
    @return: Logged addresses
    @rtype: C{list}"""
    global ROW_LIMIT   
    if limit == None or type(limit) != int or limit < 1 or limit > ROW_LIMIT:
        limit = ROW_LIMIT
    
    addresses = []
    
    try:
        dbConnection = data.open_connection()
        statement = "select * from address_log order by log_datetime desc limit %d;" % limit
        result = data.execute(dbConnection, statement)
        for row in result:
            addresses.append([row["address"], row["radar_user_id"], float(row["log_datetime"])])
        result.close()
        data.close_connection(dbConnection)
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.addresslog.get_log_addresses")
        raise
        
    return addresses

def get_log_registered_addresses(limit):
    """Gets user logged addresses.
    @param limit: Limit of addresses to get. It can be as much ROW_LIMIT.
    @type limit: C{int}
    @return: Logged user addresses
    @rtype: C{list}"""
    global ROW_LIMIT
    if limit == None or type(limit) != int or limit < 1 or limit > ROW_LIMIT: limit = ROW_LIMIT
    addresses = []
    
    try:
        dbConnection = data.open_connection()
        statement = "select address_log.address, radar_user_id, log_datetime from address_log, addresses where address_log.address = addresses.address order by log_datetime desc limit %d;" % limit
        result = data.execute(dbConnection, statement)
        for row in result:
            addresses.append([row["address"], row["radar_user_id"], float(row["log_datetime"])])
        result.close()
        data.close_connection(dbConnection)
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.addresslog.get_log_registered_addresses")
        raise
        
    return addresses

def get_last_log_modified_date():
    """Gets the last time the log has been changed.
    @return: Last time in Unix format
    @rtype: C{float}"""
    date = None
    
    try:
        dbConnection = data.open_connection()
        statement = "select last_mod_date from address_log_dates;"
        result = data.execute(dbConnection, statement)
        row = result.fetchone()
        if row: date = float(row["last_mod_date"])
        else: date = time.time()
        result.close()
        data.close_connection(dbConnection)
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.addresslog.get_last_log_modified_date")
        raise
        
    return date
    
def update_dates(updateTime):
    """Updates log modification datetimes.
    @param updateTime: Datetime to set as log last modified date in Unix format
    @type updateTime: C{float}"""
    if updateTime == None or (type(updateTime) != int and type(updateTime) != long and type(updateTime) != float):
        raise coreexceptions.SystemException("'updateTime' is not an integer or a long integer or a float")
        
    try:
        dbConnection = data.open_connection()
        statement = "delete from address_log_dates;"
        result = data.execute(dbConnection, statement)
        result.close()
        statement = "insert into address_log_dates values ('%s');" % updateTime
        result = data.execute(dbConnection, statement)
        result.close()
        data.close_connection(dbConnection)
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.addresslog.update_dates")
        raise
        
def check_log_size():
    """Determines if address log size has reached its limit and its last rows should be deleted."""  
    try:
        dbConnection = data.open_connection()
        statement1 = "select count(*) as c from address_log;"
        result1 = data.execute(dbConnection, statement1)
        row = result1.fetchone()
        
        if row:
            logSize = int(row["c"])
            result1.close()
            doReset = (logSize > RECORD_MAX)
            
            if doReset:
                rowsToDelete = logSize - RECORD_MAX
                statement2 = "delete from address_log order by log_datetime limit %s;" % rowsToDelete
                result2 = data.execute(dbConnection, statement2)
                result2.close()              
        else:
            result1.close()   
            
        data.close_connection(dbConnection)
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.addresslog.check_size")
        raise
    
def update_log_addresses(addresses, stationUserId):
    """Updates address log inserting new addresses.
    @param addresses: New addresses to log
    @type addresses: C{list}
    @param stationUserId: ID of the station user that detected the addresses
    @type stationUserId: C{str}"""
    if addresses != None and type(addresses) != list:
        raise coreexceptions.SystemException("'addresses' is not a string list")
    if stationUserId == None or (type(stationUserId) != str and type(stationUserId) != unicode) or stationUserId == "":
        raise coreexceptions.ValueNotValidException("'stationUserId' must be a not null and not empty string")

    try:
        if addresses != None and len(addresses) > 0:
            updateTime = time.time()
            loggedAddresses = []
            dbConnection = data.open_connection()
            
            for addr in addresses:
                if loggedAddresses.count(addr) == 0:
                    statement = "insert into address_log values ('%s', '%s', '%s');" % (addr, stationUserId, updateTime)
                    result = data.execute(dbConnection, statement)
                    result.close()
                    loggedAddresses.append(addr)
                    
            data.close_connection(dbConnection)
            check_log_size()
            update_dates(updateTime)
    except Exception as exc:
        errorlog.log_exception(exc.args[0], "predesys-server.core.addresslog.update_log_addresses")
        raise
